using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;

namespace CS_raytracer
{
    public partial class Form1 : Form
    {
        List<Bitmap> Movie = new List<Bitmap>();
        Bitmap BackBuffer;
        CCamera Camera;
        CScene Scene;
        public Form1()
        {
            InitializeComponent();
            BackBuffer = new Bitmap(Constants.ViewportWidth, Constants.ViewportHeight);
            Camera = new CCamera();
            Scene = new CScene();
            Scene.LoadMaterials("Materials.xml");
            Scene.PutMaterialsInList(ref MaterialList);
            Scene.LoadObjects("Scene.xml", ref Camera);
            Scene.GenerateSphereScene(30);
            textBox1.Text = "1.0";
            textBox2.Text = Camera.GetFOV().ToString();
            OutputBuffer.BackgroundImage = BackBuffer;
            OutputBuffer.Size = new Size(Constants.ViewportWidth,Constants.ViewportHeight);
            StatusText.Text = "Idle";
            bw.WorkerReportsProgress = true;
            bw.WorkerSupportsCancellation = true;
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);

            bw2.WorkerReportsProgress = false;
            bw2.WorkerSupportsCancellation = true;
            bw2.DoWork += new DoWorkEventHandler(bw2_DoWork);
        }

        private void ClearBuffer()
        {
            for (int i = 0; i < Constants.ViewportWidth; ++i)
                for (int j = 0; j < Constants.ViewportHeight; ++j)
                    BackBuffer.SetPixel(i, j, Color.Black);
        }

        private BackgroundWorker bw = new BackgroundWorker();
        private BackgroundWorker bw2 = new BackgroundWorker();
        
        private void button1_Click(object sender, EventArgs e)
        {
            //BackBuffer.SetPixel(128, 128, Color.FromArgb(255, 255, 0));
            //ClearBuffer();
/*            StatusText.Text = "Rendering";
            this.Invalidate();
            Camera.RenderScene(Scene, ref BackBuffer,this);
            OutputBuffer.Refresh();
            StatusText.Text = "Idle";
            this.Invalidate();*/
            if(!bw.IsBusy)
            {
                bw.RunWorkerAsync();
                StatusText.Text = "Rendering 0%";
            }
            
        }

        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            Movie.Clear();
            for (int i = 0; i < 360; i+=1)
            {
                if ((worker.CancellationPending == true))
                {
                    e.Cancel = true;
                    break;
                }
                else
                {
                    Camera.Position = new CVector(-100.0 * Math.Sin(Math.PI / 180 * i), 2.0, 100.0 * Math.Cos(Math.PI / 180 * i));
                    Bitmap image = new Bitmap(Constants.ViewportWidth, Constants.ViewportHeight);
                    Camera.RenderScene(Scene, ref image, this);
                    image.Save(string.Format("c:\\temp1\\image{0}.png",i),ImageFormat.Png);
                    Movie.Add(image);
                    worker.ReportProgress((int)(i * 100.0/360));
                }
            }
        }

        private void bw2_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            int i = 0;
            while(true)
            {
                if ((worker.CancellationPending == true))
                {
                    e.Cancel = true;
                    break;
                }
                else
                {
                    RefreshDisplay(i);
                    ++i;
                    System.Threading.Thread.Sleep(32);
                    if (i == Movie.Count)
                        i = 0;
                }
            }
        }

        public delegate void RefreshDisplayCallBack(int i);

        public void RefreshDisplay(int i)
        {
            if (this.InvokeRequired)
            {
                RefreshDisplayCallBack del = new RefreshDisplayCallBack(RefreshDisplay);
                object[] parameters = { i };
                this.Invoke(del,parameters);
            }
            else
            {
                OutputBuffer.BackgroundImage = Movie[i];
                OutputBuffer.Refresh();
                this.Redraw();
            }
        }

        private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            StatusText.Text = "Rendering " + (e.ProgressPercentage.ToString() + "%");
        }

        public void Redraw()
        {
            OutputBuffer.Refresh();
        }
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            Constants.Exposure = double.Parse(textBox1.Text);
        }

        private void textBox2_TextChanged(object sender, EventArgs e)
        {
            Camera.SetFOV(double.Parse(textBox2.Text));
        }

        private void MaterialList_SelectedIndexChanged(object sender, EventArgs e)
        {
            CMaterial mat = Scene.GetMaterial(MaterialList.Text);
            ColorRed.Value = (decimal)mat.color.r;
            ColorGreen.Value = (decimal)mat.color.g;
            ColorBlue.Value = (decimal)mat.color.b;
            Diffuse.Value = (decimal)mat.diffuse;
            Specular.Value = (decimal)mat.specular;
            SpecularExponent.Value = mat.specularExponent;
            ReflectionRed.Value = (decimal)mat.reflection.r;
            ReflectionGreen.Value = (decimal)mat.reflection.g;
            ReflectionBlue.Value = (decimal)mat.reflection.b;
            ReflectionScatter.Value = (decimal)mat.reflectionScatter;
            Transparency.Value = (decimal)mat.transparency;
            RefractionIndexRed.Value = (decimal)mat.refractionIndex.r;
            RefractionIndexGreen.Value = (decimal)mat.refractionIndex.g;
            RefractionIndexBlue.Value = (decimal)mat.refractionIndex.b;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            CMaterial mat = Scene.GetMaterial(MaterialList.Text);
            mat.color.r = (double)ColorRed.Value;
            mat.color.g = (double)ColorGreen.Value;
            mat.color.b = (double)ColorBlue.Value;
            mat.diffuse = (double)Diffuse.Value;
            mat.specular = (double)Specular.Value;
            mat.specularExponent = (int)SpecularExponent.Value;
            mat.reflection.r = (double)ReflectionRed.Value;
            mat.reflection.g = (double)ReflectionGreen.Value;
            mat.reflection.b = (double)ReflectionBlue.Value;
            mat.reflectionScatter = (double)ReflectionScatter.Value;
            mat.transparency = (double)Transparency.Value;
            mat.refractionIndex.r = (double)RefractionIndexRed.Value;
            mat.refractionIndex.g = (double)RefractionIndexGreen.Value;
            mat.refractionIndex.b = (double)RefractionIndexBlue.Value;
            Scene.SetMaterial(MaterialList.Text, mat);
        }

        private void button3_Click(object sender, EventArgs e)
        {
            if(!bw2.IsBusy)
            {
                bw2.RunWorkerAsync();
                StatusText.Text = "Playing";
            }
        }

        private void button4_Click(object sender, EventArgs e)
        {
            if(bw.IsBusy)
                bw.CancelAsync();
            if(bw2.IsBusy)
                bw2.CancelAsync();
        }

    }
}